var createError = require('http-errors');
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');
var fs = require('fs');
const os = require('os');
const iconv = require('iconv-lite'); // 引入 iconv-lite
const axios = require('axios');
const archiver = require('archiver');
const sanitize = require('sanitize-filename');

var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');
const multer = require('multer');
const { exec } = require('child_process');

var app = express();

// 配置 multer 的存储方式
const storage = multer.diskStorage({
  destination: function (req, file, cb) {
    const now = new Date();
    const year = now.getFullYear();
    const month = String(now.getMonth() + 1).padStart(2, '0'); // 补零，例如 03
    const uploadPath = path.join('uploads', `${year}${month}`);

    // 如果目录不存在，则创建
    if (!fs.existsSync(uploadPath)) {
      fs.mkdirSync(uploadPath, { recursive: true });
    }
    cb(null, uploadPath);
  },
  filename: function (req, file, cb) {
    // 使用 iconv-lite 将文件名从原始编码（如 GBK）转换为 UTF-8
    const originalName = file.originalname;
    const decodedName = iconv.decode(Buffer.from(originalName, 'binary'), 'utf-8'); // 转换为 UTF-8
    cb(null, decodedName); // 使用转换后的文件名
  }
});

const upload = multer({ storage: storage });

// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');

app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));

app.use('/', indexRouter);
app.use('/users', usersRouter);

// 全局变量来跟踪是否有命令正在执行
let isCommandRunning = false;

app.post('/upload', upload.single('file'), (req, res) => {
  try {
    const filePath = req.file.path; // 文件保存路径
    const originalName = req.file.originalname; // 文件原始名称
    const fileSize = req.file.size; // 文件大小

    console.log(`文件保存路径: ${filePath}`); // 输出文件保存路径

    // 自动拼接完整的 APK 文件路径
    const fullApkFilePath = path.join(__dirname, filePath);

    // 检查并移除旧的签名文件
    const now = new Date();
    const year = now.getFullYear();
    const month = String(now.getMonth() + 1).padStart(2, '0'); // 补零，例如 03
    const uploadPath = path.join('uploads', `${year}${month}`);
    const signedFilePath = path.join(uploadPath, originalName.replace('.apk', '_signed.apk'));

    if (fs.existsSync(signedFilePath)) {
      fs.unlinkSync(signedFilePath); // 移除旧的签名文件
      console.log(`已移除旧的签名文件: ${signedFilePath}`);
    }

    console.log('fullApkFilePath:', fullApkFilePath);

    // 执行签名命令
    if (isCommandRunning) {
      console.log('命令正在执行中，请稍后再试。');
      return res.json({ code: 400, msg: '命令正在执行中，请稍后再试。' });
    }

    isCommandRunning = true; // 设置命令正在执行的标志

    if (os.platform() === 'win32') {
      // 使用 spawn 代替 exec
      const spawn = require('child_process').spawn;
      const javaProcess = spawn('java', [
        '-jar', 
        'C:\\autosign\\autoSign-2.0.jar', 
        '-configFilePath', 
        'C:\\autosign\\signConfig.json', 
        '-toolsPath', 
        'C:\\autosign\\toolsPathConfig.json', 
        '-apkFilePath', 
        fullApkFilePath
      ], { 
        cwd: 'C:\\autosign',
        windowsHide: true,
        stdio: 'pipe'
      });

      javaProcess.stdout.on('data', (data) => {
        console.log(`stdout: ${data}`);
      });

      javaProcess.stderr.on('data', (data) => {
        console.error(`stderr: ${data}`);
      });

      javaProcess.on('error', (error) => {
        console.error('Java 进程启动失败:', error);
        isCommandRunning = false;
        return res.json({ code: 500, msg: 'Java 进程启动失败，请检查 Java 安装和环境变量设置' });
      });

      javaProcess.on('close', (code) => {
        isCommandRunning = false; // 重置命令执行标志
        console.log(`子进程退出，退出码 ${code}`);
        if (code === 0) {
          return res.json({ code: 200, msg: '签名过程成功' });
        } else {
          console.error(`签名过程失败，退出码 ${code}`);
          return res.json({ code: 500, msg: `签名过程失败，退出码 ${code}` });
        }
      });

      // 启动Java进程后，直接返回，等待close事件处理响应
      return;

    } else {
      // 处理其他平台的命令
      let cmdCommand;
      if (os.platform() === 'darwin') {
        cmdCommand = `osascript -e 'tell application "Terminal" to do script "cd /autosign && java -jar autoSign-2.0.jar -configFilePath /autosign/signConfig.json -toolsPath /autosign/toolsPathConfig.json -apkFilePath ${fullApkFilePath} && sleep 3"'`;
      } else {
        cmdCommand = `gnome-terminal -- bash -c 'cd /autosign && java -jar autoSign-2.0.jar -configFilePath /autosign/signConfig.json -toolsPath /autosign/toolsPathConfig.json -apkFilePath ${fullApkFilePath}; sleep 3; exec bash'`;
      }

      exec(cmdCommand, (error, stdout, stderr) => {
        isCommandRunning = false;
        if (error) {
          console.error(`exec error: ${error}`);
          return res.json({ code: 500, msg: '执行命令失败' }); // 返回错误响应
        }
        console.log(`stdout: ${stdout}`);
        console.error(`stderr: ${stderr}`);
        return res.json({ code: 200, msg: '文件上传成功' }); // 在这里发送成功响应
      });
    }
  } catch (err) {
    console.error('上传处理失败:', err);
    isCommandRunning = false;
    return res.json({ code: 500, msg: '上传处理失败' });
  }
});

// 下载签名文件接口
app.get('/download-signed-apk', (req, res) => {
  const fileName = req.query.fileName; // 从查询参数获取文件名
  const now = new Date();
  const year = now.getFullYear();
  const month = String(now.getMonth() + 1).padStart(2, '0'); // 补零，例如 03
  const uploadPath = path.join('uploads', `${year}${month}`);
  
  const filePath = path.resolve(__dirname, uploadPath, fileName); // 拼接完整的文件路径
  console.log('filePath', filePath, fileName);

  // 检查文件是否存在
  if (!fs.existsSync(filePath)) {
    return res.json({ code: 404, msg: '未找到签名文件' }); // 返回 404 错误
  }

  // 获取局域网 IP 地址
  const networkInterfaces = os.networkInterfaces();
  let localIP = '';
  for (const interfaceName in networkInterfaces) {
    for (const net of networkInterfaces[interfaceName]) {
      if (net.family === 'IPv4' && !net.internal) {
        localIP = net.address; // 获取第一个非内部的 IPv4 地址
        break;
      }
    }
    if (localIP) break; // 找到后退出循环
  }

  // 使用局域网 IP 地址生成下载链接
  const downloadUrl = `http://${localIP}:8889/download-signed-apk?fileName=${encodeURIComponent(fileName)}`;
  
  // 使用 res.download 进行文件下载
  res.download(filePath, fileName, (err) => {
    if (err) {
      // 处理下载错误
      if (err.code === 'ECONNABORTED') {
        console.warn('下载请求被中止:', err);
        return; // 不再发送响应
      }
      console.error('下载文件失败:', err);
      // 处理其他错误
      return res.json({ code: 500, msg: '下载文件失败' });
    }
  });
});

// 是否签名接口
app.get('/check-signed-file', (req, res) => {
  let fileName = req.query.fileName; // 从查询参数获取当前上传的文件名
  console.log('Received fileName:', fileName);

  if (!fileName) {
    return res.json({ code: 400, msg: '缺少文件名参数' }); // 如果没有文件名参数，返回 400 错误
  }

  // 检查文件名是否符合预期格式
  if (!fileName.endsWith('.apk')) {
    return res.json({ code: 400, msg: '文件名格式不正确，必须以 .apk 结尾' }); // 返回 400 错误
  }
  const signedFileName = fileName.replace('.apk', '_signed.apk'); // 生成签名文件名
  const now = new Date();
  const year = now.getFullYear();
  const month = String(now.getMonth() + 1).padStart(2, '0'); // 补零，例如 03
  const uploadPath = path.join('uploads', `${year}${month}`);

  // 检查上传路径是否存在
  if (!fs.existsSync(uploadPath)) {
    return res.json({ code: 500, msg: `上传路径不存在: ${uploadPath}` }); // 返回 500 错误
  }

  fs.readdir(uploadPath, (err, files) => {
    if (err) {
      console.error('读取目录失败:', err);
      return res.json({ code: 500, msg: '读取目录失败' });
    }

    const signedFile = files.find(file => file === signedFileName); // 检查是否存在对应的签名文件
    if (signedFile) {
      const downloadUrl = `http://localhost:8889/download-signed-apk?fileName=${encodeURIComponent(signedFile)}`; // 生成下载链接
      return res.json({ code: 200, msg: '签名文件存在', downloadUrl, fileName: signedFile });
    }
    return res.json({ code: 404, msg: '签名文件不存在' });
  });
});

// ========== 素材下载：页面 ==========
app.get('/materials', (req, res) => {
  res.render('materials', (err, html) => {
    if (err) {
      console.error('Render materials error:', err);
      return res.status(500).json({ code: 500, msg: '服务器错误' });
    }
    res.send(html);
  });
});

// ========== 素材下载：工具函数 ==========
async function fetchVivoSearchAll(keyword) {
  const searchUrl = 'https://h5-api.appstore.vivo.com.cn/h5appstore/search/result-list';
  let pageIndex = 1;
  let maxPage = 1;
  const allApps = [];

  do {
    try {
      const resp = await axios.post(`${searchUrl}?imei=1234567890&av=18&app_version=2100&pictype=webp&h5_websource=h5appstore&key=${encodeURIComponent(keyword)}&page_index=${pageIndex}&apps_per_page=20&target=local&cfrom=2`, null, {
        headers: {
          'Accept': 'application/json, text/plain, */*',
          'Origin': 'https://h5.appstore.vivo.com.cn',
          'Referer': 'https://h5.appstore.vivo.com.cn/',
          'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
          'Connection': 'keep-alive',
          'Cache-Control': 'no-cache'
        },
        timeout: 30000,
        maxRedirects: 5,
        validateStatus: function (status) {
          return status >= 200 && status < 300;
        }
      });
      const data = resp.data && resp.data.data && resp.data.data.appSearchResponse;
      if (!data || !data.value) break;
      maxPage = Number(data.maxPage || 1);
      
      // 根据产品名模糊匹配过滤
      for (const item of data.value) {
        const appName = (item.title_zh || '').toLowerCase();
        const searchKeyword = keyword.toLowerCase();
        
        // 智能匹配：检查应用名是否包含关键词或关键词的变体
        let isMatch = false;
        
        // 1. 直接包含匹配
        if (appName.includes(searchKeyword)) {
          isMatch = true;
        }
        
        // 2. 去除空格后匹配
        const cleanAppName = appName.replace(/\s+/g, '');
        const cleanKeyword = searchKeyword.replace(/\s+/g, '');
        if (cleanAppName.includes(cleanKeyword)) {
          isMatch = true;
        }
        
        // 3. 关键词长度大于2时，检查是否包含关键词的主要部分
        // if (searchKeyword.length > 2) {
        //   const keywordParts = searchKeyword.split('').filter(char => char !== ' ');
        //   const hasAllParts = keywordParts.every(part => appName.includes(part));
        //   if (hasAllParts && keywordParts.length >= 2) {
        //     isMatch = true;
        //   }
        
        if (isMatch) {
          allApps.push(item);
          console.log(`✓ 匹配到应用: ${item.title_zh}`);
        }
      }
      pageIndex += 1;
      // 添加延迟避免请求过快
      await new Promise(resolve => setTimeout(resolve, 1000));
    } catch (error) {
      console.error(`搜索第${pageIndex}页失败:`, error.message);
      if (pageIndex === 1) {
        throw error; // 第一页失败直接抛出错误
      }
      break; // 其他页失败则停止
    }
  } while (pageIndex <= maxPage);

  return allApps;
}

async function fetchVivoDetail(appId) {
  const url = `https://h5-api.appstore.vivo.com.cn/detail/${appId}?frompage=messageh5&imei=1234567890&av=18&app_version=2100&pictype=webp&h5_websource=h5appstore`;
  try {
    const resp = await axios.get(url, {
      headers: {
        'Accept': 'application/json, text/plain, */*',
        'Origin': 'https://h5.appstore.vivo.com.cn',
        'Referer': 'https://h5.appstore.vivo.com.cn/',
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
        'Connection': 'keep-alive',
        'Cache-Control': 'no-cache'
      },
      timeout: 30000,
      maxRedirects: 5,
      validateStatus: function (status) {
        return status >= 200 && status < 300;
      }
    });
    return resp.data;
  } catch (error) {
    console.error(`获取应用详情失败 (ID: ${appId}):`, error.message);
    return null;
  }
}

async function downloadFileTo(url, filePath) {
  const dir = path.dirname(filePath);
  if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
  try {
    const response = await axios.get(url, { 
      responseType: 'stream', 
      timeout: 30000,
      maxRedirects: 5,
      headers: {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'
      }
    });
    await new Promise((resolve, reject) => {
      const writer = fs.createWriteStream(filePath);
      response.data.pipe(writer);
      writer.on('finish', resolve);
      writer.on('error', reject);
    });
  } catch (error) {
    console.error(`下载文件失败 (${url}):`, error.message);
    throw error;
  }
}

async function zipDirectory(sourceDir, zipFilePath) {
  await new Promise((resolve, reject) => {
    const output = fs.createWriteStream(zipFilePath);
    const archive = archiver('zip', { zlib: { level: 9 } });
    output.on('close', resolve);
    archive.on('error', reject);
    archive.pipe(output);
    archive.directory(sourceDir, false);
    archive.finalize();
  });
}

// ========== 素材下载：搜索并打包 ==========
app.post('/search-materials', express.json(), async (req, res) => {
  try {
    const keyword = (req.body.keyword || '').trim();
    if (!keyword) {
      return res.status(400).json({ code: 400, msg: '请输入产品名' });
    }

    // 清空uploads目录
    const uploadsDir = path.join(__dirname, 'uploads');
    if (fs.existsSync(uploadsDir)) {
      const files = fs.readdirSync(uploadsDir);
      for (const file of files) {
        const filePath = path.join(uploadsDir, file);
        const stat = fs.statSync(filePath);
        if (stat.isDirectory()) {
          fs.rmSync(filePath, { recursive: true, force: true });
        } else {
          fs.unlinkSync(filePath);
        }
      }
    }

    const ts = Date.now();
    const baseDir = path.join(__dirname, 'uploads', `materials_${ts}`);
    if (!fs.existsSync(baseDir)) fs.mkdirSync(baseDir, { recursive: true });

    const apps = await fetchVivoSearchAll(keyword);
    console.log(`找到 ${apps.length} 个应用，开始下载素材...`);
    
    for (let i = 0; i < apps.length; i++) {
      const app = apps[i];
      const appId = app.id;
      if (!appId) continue;
      
      console.log(`处理应用 ${i + 1}/${apps.length}: ${app.title_zh || appId}`);
      
      const detail = await fetchVivoDetail(appId);
      if (!detail) {
        console.log(`跳过应用 ${appId}，获取详情失败`);
        continue;
      }
      
      const folderName = sanitize(detail.title_zh || String(appId));
      const appDir = path.join(baseDir, folderName);
      if (!fs.existsSync(appDir)) fs.mkdirSync(appDir, { recursive: true });

      // 下载图标
      if (detail.icon_url) {
        try {
          const iconExt = path.extname(new URL(detail.icon_url).pathname) || '.png';
          await downloadFileTo(detail.icon_url, path.join(appDir, `icon${iconExt}`));
          console.log(`  ✓ 图标下载完成`);
        } catch (e) {
          console.log(`  ✗ 图标下载失败: ${e.message}`);
        }
      }
      
      // 下载截图
      if (Array.isArray(detail.screenshotList)) {
        let successCount = 0;
        for (let idx = 1; idx <= detail.screenshotList.length; idx++) {
          try {
            const img = detail.screenshotList[idx - 1];
            const ext = path.extname(new URL(img).pathname) || '.png';
            await downloadFileTo(img, path.join(appDir, `screenshot_${idx}${ext}`));
            successCount++;
          } catch (e) {
            console.log(`  ✗ 截图 ${idx} 下载失败: ${e.message}`);
          }
        }
        console.log(`  ✓ 截图下载完成 (${successCount}/${detail.screenshotList.length})`);
      }
      
      // 添加延迟避免请求过快
      if (i < apps.length - 1) {
        await new Promise(resolve => setTimeout(resolve, 500));
      }
    }

    const zipName = `materials_${ts}.zip`;
    const zipPath = path.join(__dirname, 'uploads', zipName);
    await zipDirectory(baseDir, zipPath);

    const host = req.headers.host || `localhost:${process.env.PORT || 8889}`;
    const downloadUrl = `${req.protocol}://${host}/download-zip?file=${encodeURIComponent(zipName)}`;
    return res.json({ code: 200, msg: '处理完成', downloadUrl });
  } catch (err) {
    console.error('search-materials error:', err);
    return res.status(500).json({ code: 500, msg: '处理失败' });
  }
});

// ========== 素材下载：下载压缩包 ==========
app.get('/download-zip', (req, res) => {
  const file = (req.query.file || '').trim();
  if (!file) return res.status(400).json({ code: 400, msg: '缺少文件名' });
  const filePath = path.join(__dirname, 'uploads', file);
  if (!fs.existsSync(filePath)) return res.status(404).json({ code: 404, msg: '文件不存在' });
  res.download(filePath, file);
});

// error handler
app.use(function(err, req, res, next) {
  // set locals, only providing error in development
  res.locals.message = err.message;
  res.locals.error = req.app.get('env') === 'development' ? err : {};

  console.error('Unhandled error:', err);
  res.status(err.status || 500).json({ code: err.status || 500, msg: '服务器错误' });
});

module.exports = app;
const port = process.env.PORT || 8889; // 使用环境变量 PORT 或默认端口 3001
app.listen(port, () => {
  console.log(`服务器正在运行，访问地址：http://localhost:${port}`);
});